"""
Split configuration dialog.
"""

import os
from typing import Optional, List, Dict, Any

from PyQt6.QtWidgets import (
    QDialog, QVBoxLayout, QHBoxLayout, QFormLayout,
    QLineEdit, QSpinBox, QDoubleSpinBox, QComboBox, QLabel, QPushButton,
    QTextEdit, QGroupBox, QRadioButton, QButtonGroup,
    QFileDialog, QMessageBox, QProgressBar, QDialogButtonBox,
    QCheckBox, QSlider
)
from PyQt6.QtCore import Qt, pyqtSlot, QThread, QTimer, QCoreApplication
from PyQt6.QtGui import QFont

from ...core.pdf_processor import PDFProcessor
from ...core.pdf_splitter import PDFSplitter, SplitMode, SplitWorker


class SplitDialog(QDialog):
    """Dialog for configuring PDF split operations."""

    def __init__(self, processor: PDFProcessor, splitter: PDFSplitter,
                 file_path: Optional[str], parent=None):
        super().__init__(parent)
        self.processor = processor
        self.splitter = splitter
        self.file_path = file_path
        self.split_thread: Optional[QThread] = None
        self.split_worker: Optional[SplitWorker] = None
        self._is_splitting = False

        self.init_ui()

    def init_ui(self):
        """Initialize the user interface."""
        self.setWindowTitle("Split PDF")
        self.setMinimumSize(500, 600)
        self.resize(600, 700)

        # Main layout
        layout = QVBoxLayout(self)

        # Split mode selection
        mode_group = QGroupBox("Split Mode")
        mode_layout = QVBoxLayout(mode_group)

        self.mode_button_group = QButtonGroup(self)
        self.range_mode = QRadioButton("Split by Page Range")
        self.pages_mode = QRadioButton("Split by Fixed Page Count")
        self.bookmark_mode = QRadioButton("Split by Bookmarks")
        self.size_mode = QRadioButton("Split by File Size")

        self.mode_button_group.addButton(self.range_mode, 0)
        self.mode_button_group.addButton(self.pages_mode, 1)
        self.mode_button_group.addButton(self.bookmark_mode, 2)
        self.mode_button_group.addButton(self.size_mode, 3)

        mode_layout.addWidget(self.range_mode)
        mode_layout.addWidget(self.pages_mode)
        mode_layout.addWidget(self.bookmark_mode)
        mode_layout.addWidget(self.size_mode)

        # Range mode settings
        self.range_group = QGroupBox("Page Range Settings")
        range_layout = QFormLayout(self.range_group)

        self.range_input = QLineEdit()
        self.range_input.setPlaceholderText("e.g., 1-5, 10, 15-20")
        range_layout.addRow("Ranges:", self.range_input)

        # Pages mode settings
        self.pages_group = QGroupBox("Fixed Page Count Settings")
        pages_layout = QFormLayout(self.pages_group)

        self.pages_per_file = QSpinBox()
        self.pages_per_file.setMinimum(1)
        self.pages_per_file.setMaximum(999)
        self.pages_per_file.setValue(10)
        pages_layout.addRow("Pages per file:", self.pages_per_file)

        # Bookmark mode settings
        self.bookmark_group = QGroupBox("Bookmark Settings")
        bookmark_layout = QFormLayout(self.bookmark_group)

        self.bookmark_level = QSpinBox()
        self.bookmark_level.setMinimum(1)
        self.bookmark_level.setMaximum(10)
        self.bookmark_level.setValue(1)
        bookmark_layout.addRow("Level:", self.bookmark_level)

        # File size mode settings
        self.size_group = QGroupBox("File Size Settings")
        size_layout = QFormLayout(self.size_group)

        self.max_size_mb = QDoubleSpinBox()
        self.max_size_mb.setMinimum(0.1)
        self.max_size_mb.setMaximum(1000.0)
        self.max_size_mb.setValue(10.0)
        self.max_size_mb.setSuffix(" MB")
        self.max_size_mb.setDecimals(1)
        size_layout.addRow("Maximum file size:", self.max_size_mb)

        # Output settings
        output_group = QGroupBox("Output Settings")
        output_layout = QFormLayout(output_group)

        self.output_dir = QLineEdit()
        if self.file_path:
            self.output_dir.setText(os.path.dirname(self.file_path))
        output_layout.addRow("Output Directory:", self.output_dir)

        browse_btn = QPushButton("Browse...")
        browse_btn.clicked.connect(self.browse_output_dir)
        output_layout.addRow("", browse_btn)

        self.filename_template = QLineEdit("{original_name}_{part}")
        output_layout.addRow("Filename Template:", self.filename_template)

        self.preserve_metadata = QCheckBox("Preserve document metadata")
        self.preserve_metadata.setChecked(True)
        output_layout.addRow("", self.preserve_metadata)

        # Preview section
        preview_group = QGroupBox("Preview")
        preview_layout = QVBoxLayout(preview_group)

        self.preview_text = QTextEdit()
        self.preview_text.setReadOnly(True)
        self.preview_text.setMaximumHeight(150)
        preview_layout.addWidget(self.preview_text)

        preview_btn = QPushButton("Preview Split")
        preview_btn.clicked.connect(self.preview_split)
        preview_layout.addWidget(preview_btn)

        # Progress bar
        self.progress_bar = QProgressBar()
        self.progress_bar.setVisible(False)
        layout.addWidget(self.progress_bar)

        # Dialog buttons
        button_box = QDialogButtonBox(
            QDialogButtonBox.StandardButton.Ok |
            QDialogButtonBox.StandardButton.Cancel
        )
        button_box.accepted.connect(self.accept)
        button_box.rejected.connect(self.reject)
        self.ok_button = button_box.button(QDialogButtonBox.StandardButton.Ok)
        self.ok_button.setText("Split")

        layout.addWidget(mode_group)
        layout.addWidget(self.range_group)
        layout.addWidget(self.pages_group)
        layout.addWidget(self.bookmark_group)
        layout.addWidget(self.size_group)
        layout.addWidget(output_group)
        layout.addWidget(preview_group)
        layout.addWidget(button_box)

        # Setup connections
        self.mode_button_group.buttonClicked.connect(self.on_mode_changed)
        self.range_mode.setChecked(True)
        self.on_mode_changed()

    def on_mode_changed(self):
        """Handle split mode change."""
        mode = self.mode_button_group.checkedId()

        # Hide all groups
        self.range_group.setVisible(False)
        self.pages_group.setVisible(False)
        self.bookmark_group.setVisible(False)
        self.size_group.setVisible(False)

        # Show relevant group
        if mode == 0:  # Range mode
            self.range_group.setVisible(True)
        elif mode == 1:  # Pages mode
            self.pages_group.setVisible(True)
        elif mode == 2:  # Bookmark mode
            self.bookmark_group.setVisible(True)

            # Check if document has bookmarks
            outline = self.processor.get_outline()
            if not outline:
                self.bookmark_mode.setEnabled(False)
                self.bookmark_mode.setToolTip("Document has no bookmarks")
            else:
                self.bookmark_mode.setEnabled(True)
        elif mode == 3:  # Size mode
            self.size_group.setVisible(True)

    def browse_output_dir(self):
        """Browse for output directory."""
        dir_path = QFileDialog.getExistingDirectory(
            self,
            "Select Output Directory",
            self.output_dir.text() or os.path.expanduser("~")
        )
        if dir_path:
            self.output_dir.setText(dir_path)

    def preview_split(self):
        """Preview the split operation."""
        if not self.validate_inputs():
            return

        mode = self.mode_button_group.checkedId()
        output_dir = self.output_dir.text()

        preview_text = ""
        try:
            if mode == 0:  # Range mode
                ranges_text = self.range_input.text()
                ranges = self.splitter.parse_page_ranges(ranges_text, self.processor.get_page_count())
                preview_text = f"Will create {len(ranges)} files:\n\n"
                for i, split_range in enumerate(ranges):
                    page_count = split_range.end - split_range.start + 1
                    preview_text += f"File {i+1}: Pages {split_range.start}-{split_range.end} ({page_count} pages)\n"

            elif mode == 1:  # Pages mode
                pages_per_file = self.pages_per_file.value()
                total_pages = self.processor.get_page_count()
                num_files = (total_pages + pages_per_file - 1) // pages_per_file
                preview_text = f"Will create {num_files} files with {pages_per_file} pages each\n\n"
                for i in range(num_files):
                    start = i * pages_per_file + 1
                    end = min(start + pages_per_file - 1, total_pages)
                    preview_text += f"File {i+1}: Pages {start}-{end}\n"

            elif mode == 2:  # Bookmark mode
                level = self.bookmark_level.value()
                outline = self.processor.get_outline()
                bookmarks = [b for b in outline if b.get('level', 0) == level - 1 and b.get('type') == 'page']
                preview_text = f"Will split at {len(bookmarks)} bookmarks (level {level}):\n\n"
                for i, bookmark in enumerate(bookmarks):
                    title = bookmark.get('title', 'Untitled')
                    page = bookmark.get('page', 0) + 1
                    preview_text += f"{title} (starts at page {page})\n"

            elif mode == 3:  # File size mode
                max_size_mb = self.max_size_mb.value()
                total_size = os.path.getsize(self.processor.get_file_path()) / (1024 * 1024)  # Convert to MB
                estimated_files = int(total_size / max_size_mb) + 1
                preview_text = f"Will split into approximately {estimated_files} files\n"
                preview_text += f"Maximum file size: {max_size_mb} MB\n"
                preview_text += f"Original file size: {total_size:.2f} MB\n\n"
                preview_text += "Note: Actual file sizes may vary based on content"

        except Exception as e:
            preview_text = f"Error: {str(e)}"

        self.preview_text.setText(preview_text)

    def validate_inputs(self) -> bool:
        """Validate input fields."""
        output_dir = self.output_dir.text().strip()
        if not output_dir:
            QMessageBox.warning(self, "Invalid Input", "Please specify an output directory.")
            return False

        if not os.path.exists(output_dir):
            QMessageBox.warning(self, "Invalid Input", "Output directory does not exist.")
            return False

        mode = self.mode_button_group.checkedId()
        if mode == 0:  # Range mode
            range_text = self.range_input.text().strip()
            if not range_text:
                QMessageBox.warning(self, "Invalid Input", "Please specify page ranges.")
                return False

        return True

    def accept(self):
        """Execute the split operation."""
        if not self.validate_inputs():
            return

        # Show progress bar
        self.progress_bar.setVisible(True)
        self.progress_bar.setRange(0, 0)  # Indeterminate
        self.ok_button.setEnabled(False)

        # Get parameters
        mode = self.mode_button_group.checkedId()
        output_dir = self.output_dir.text()

        # Create split worker
        if mode == 0:  # Range mode
            ranges_text = self.range_input.text()
            ranges = self.splitter.parse_page_ranges(ranges_text, self.processor.get_page_count())
            kwargs = {'ranges': ranges, 'output_dir': output_dir}
            split_mode = SplitMode.BY_RANGE

        elif mode == 1:  # Pages mode
            pages_per_file = self.pages_per_file.value()
            kwargs = {'pages_per_file': pages_per_file, 'output_dir': output_dir}
            split_mode = SplitMode.BY_PAGES

        elif mode == 2:  # Bookmark mode
            level = self.bookmark_level.value()
            kwargs = {'level': level, 'output_dir': output_dir}
            split_mode = SplitMode.BY_BOOKMARK

        else:  # Size mode
            max_size_mb = self.max_size_mb.value()
            kwargs = {'max_size_mb': max_size_mb, 'output_dir': output_dir}
            split_mode = SplitMode.BY_SIZE

        # Start split operation in background thread
        self.split_worker = SplitWorker(self.processor, split_mode, **kwargs)
        self.split_thread = QThread()
        self.split_worker.moveToThread(self.split_thread)

        # Connect signals
        self.split_worker.progress.connect(self.progress_bar.setValue)
        self.split_worker.finished.connect(self.on_split_finished)
        self.split_worker.error.connect(self.on_split_error)
        self.split_thread.started.connect(self.split_worker.run)

        # Start operation
        self._is_splitting = True
        self.split_thread.start()

    @pyqtSlot(list)
    def on_split_finished(self, results: List[Dict[str, Any]]):
        """Handle split completion."""
        # Hide progress bar
        self.progress_bar.setVisible(False)
        self.ok_button.setEnabled(True)
        self._is_splitting = False

        # Show results
        successful = sum(1 for r in results if r.success)
        total = len(results)

        if successful == total:
            QMessageBox.information(
                self,
                "Split Complete",
                f"Successfully created {successful} files in:\n{self.output_dir.text()}"
            )
            self.accept()  # Close dialog
        else:
            QMessageBox.warning(
                self,
                "Split Partially Complete",
                f"Only {successful} out of {total} files were created successfully.\n"
                "Check the output directory for details."
            )

        # Schedule thread cleanup
        QTimer.singleShot(100, self._cleanup_thread)

    @pyqtSlot(str)
    def on_split_error(self, error: str):
        """Handle split error."""
        # Hide progress bar
        self.progress_bar.setVisible(False)
        self.ok_button.setEnabled(True)
        self._is_splitting = False

        QMessageBox.critical(
            self,
            "Split Failed",
            f"Failed to split PDF:\n{error}"
        )

        # Schedule thread cleanup
        QTimer.singleShot(100, self._cleanup_thread)

    def _cleanup_thread(self):
        """Clean up thread and worker."""
        if self.split_thread:
            if self.split_thread.isRunning():
                self.split_thread.quit()
                self.split_thread.wait(500)
            # Ensure thread is deleted in main thread
            QCoreApplication.processEvents()
            self.split_thread.deleteLater()
            self.split_thread = None
        self.split_worker = None

    def closeEvent(self, event):
        """Handle dialog close event."""
        # Cancel any ongoing operation
        if self._is_splitting and self.split_worker:
            self.split_worker.cancel()

        # Clean up thread
        if self.split_thread:
            self.split_thread.quit()
            self.split_thread.wait(1000)
            if self.split_thread.isRunning():
                self.split_thread.terminate()
                self.split_thread.wait(500)
            self.split_thread = None
            self.split_worker = None

        super().closeEvent(event)

    def reject(self):
        """Handle dialog rejection."""
        # Cancel any ongoing operation
        if self._is_splitting and self.split_worker:
            self.split_worker.cancel()

        # Clean up thread
        if self.split_thread:
            self.split_thread.quit()
            self.split_thread.wait(1000)
            if self.split_thread.isRunning():
                self.split_thread.terminate()
                self.split_thread.wait(500)
            self.split_thread = None
            self.split_worker = None

        super().reject()